﻿// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Microsoft.Internal
{
    internal static class LazyInit
    {
        /// <summary>
        /// Lazily init an item and return stats as to whether or not you were the winner who
        /// succeeded in initing that item. Takes a delegate that creates the object to be
        /// initialized with, that delegate needs to be idempotent.
        /// 
        /// A common example might be initing some static member f of type Foo:
        /// 
        ///     class Bar
        ///     {
        ///         static Foo f;
        ///         public static Foo F
        ///         {
        ///             get
        ///             {
        ///                 LazyInit.Init(ref f, () => new Foo());
        ///                 return f;
        ///             }
        ///         }
        ///     }
        /// </summary>
        /// <returns>Whether or not this particular call to Init was responsible for Initializing the member</returns>
        public static T Init<T>(ref T itemToInit, Func<T> lazyCreator)
            where T : class
        {
            if (null != itemToInit)
                return itemToInit;

            return Init2(ref itemToInit, lazyCreator);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        static T Init2<T>(ref T itemToInit, Func<T> lazyCreator)
            where T : class
        {
            Interlocked.CompareExchange(ref itemToInit, lazyCreator(), null);
            return itemToInit;
        }
    }
}